import pandas as pd  # 导入Pandas库,并以pd作为别名，使用Pandas读取Excel文件的数据
import tkinter as tk  # 导入Tkinter库,并以tk作为别名，用于创建GUI应用程序的界面。
from tkinter import filedialog  # filedialog用于选择文件对话框。
from pathlib import Path  # folder_path = Path(folder_entry.get())语句中使用该功能
from openpyxl import load_workbook  # load_workbook()用于读取Excel文件
from openpyxl.utils.dataframe import dataframe_to_rows  # 用于将DataFrame转换为行列表,逐行追加到工作表

# 这两行代码是我们GUI程序的起始,创建主窗口,为后续组件提供容器。
window = tk.Tk()  # 创建一个Tkinter窗口,命名为window。这是我们整个GUI的主窗口。
window.title('汇总工具')  # 设置窗口的标题为'汇总工具'。

# 输入框，这两行代码用于在主窗口window上添加一个Frame(框架),用于容纳我们的输入文件夹路径的组件。
folder_frame = tk.Frame(window)  # 这行创建一个Frame(框架),作为容器添加到window主窗口上（用来读取输入文件夹）。
folder_frame.pack()  # 这行使用pack布局管理器,将folder_frame添加到window主窗口上,显示出来。

label = tk.Label(folder_frame, text='选择输入文件夹:')  # 在框架上添加一个标签
label.pack(side=tk.LEFT)  # 这两行在folder_frame上添加一个'选择输入文件夹:'标签,并左对齐。

folder_path = tk.StringVar()  # 获取输入框和文件选择框中的路径和文件名,赋值给相应的变量。
folder_entry = tk.Entry(folder_frame, textvariable=folder_path)  # 获取输入框和文件选择框中的路径和文件名,赋值给相应的变量。
folder_entry.pack(side=tk.LEFT)  # 这三行添加一个输入框到folder_frame,并左对齐。folder_path为输入框中的内容绑定的变量。
folder_button = tk.Button(folder_frame, text='浏览', command=lambda: folder_path.set(filedialog.askdirectory()))
folder_button.pack(side=tk.RIGHT)  # 这两行添加一个'浏览'按钮到fold_frame,并右对齐。

# 输出框
file_frame = tk.Frame(window)
file_frame.pack()  # 这两行添加一个Frame到window主窗口,用于容纳输出文件名的组件。
label = tk.Label(file_frame, text='选择输出文件名:')
label.pack(side=tk.LEFT)  # 这两行在file_frame上添加一个'选择输出文件名:'标签,并左对齐。
file_path = tk.StringVar()  # 获取输入框和文件选择框中的路径和文件名,赋值给相应的变量。
file_entry = tk.Entry(file_frame, textvariable=file_path)
file_entry.insert(0, 'result.xlsx')
file_entry.pack(side=tk.LEFT)  # 这四行添加输出文件输入框file_entry到file_frame,默认文件名为result.xlsx,获取输入文件名到file_path变量,并左对齐

def convert():
    folder_path = Path(folder_entry.get())  #  获取输入文件夹路径,保存在folder_path变量。
    file_path = Path(file_entry.get())  # 获取输出文件名,保存在file_path变量。
    writer_path = folder_path / file_path # 组合folder_path和file_path,获得输出文件完整路径,保存在writer_path变量，输出文件也保存在输入目录内。

    # 读取Excel模板文件
    template_path = writer_path  # 获取模板文件路径
    wb = load_workbook(template_path)  # 读取模板文件
    ws1 = wb['Sheet1']  # ws1表示Sheet1工作表，可以按需调整Sheet1的名称
    ws2 = wb['Sheet2']  # ws2表示Sheet2工作表，可以按需调整Sheet2的名称
    # 通过ws1和ws2对象,可以操作对应的工作表,如读取数据、追加数据等。

    # 读取所有excel文件
    excel_files = folder_path.glob('*.xlsx')  # 读取输入文件夹path下所有以.xlsx结尾的Excel文件,赋值给excel_files。
    excel_files = [f for f in excel_files if not f.name.startswith(('~$', '.')) and len(f.name) > 11]  # 过滤系统临时文件，只保留文件名不以~$和.开头,且长度大于11的文件。

    # Read sheets using Pandas
    df1 = pd.DataFrame()  # df1初始化
    df2 = pd.DataFrame()  # df2初始化
    for f in excel_files:
        df1_temp = pd.read_excel(f, sheet_name='Sheet1', header=0, dtype={'col1': str, 'col2': str, 'col3': str, 'col4': str, 'col5': str, 'col6': str, 'col7': str}, engine='openpyxl').copy()    # 指定列数据格式
        df1_temp = df1_temp[df1_temp['col1'].notnull()]  # 剔除col1列中，值为空的无效记录。
        df1_temp['日期'] = pd.to_datetime(df1_temp['日期']).dt.strftime('%Y/%m/%d')   # 按需调整日期单元格的格式如：'%Y年%m月%d日'
        df1_temp['col1'].fillna(method='ffill', inplace=True)  # 拆分合并的单元格，并给拆分后的单元格赋值。
        df1_temp['序号'] = temp_df['序号'].replace('合计', '小计') # 把原表格中“序号”列中的“合计”单元格的值改为“小计” 。
        df1 = pd.concat([df1, df1_temp])  # 把文件夹中全部Excel文件中的Sheet1的数据追加到模板文件的Sheet1的数据框中。

        df2_temp = pd.read_excel(f, sheet_name='Sheet2', header=0, dtype={'col1': str, 'col2': str, 'col3': str}, engine='openpyxl').copy()    # 指定列数据格式：str 文本；int 整数；float 浮点数
        df2_temp = df2_temp[df2_temp['col1'].notnull()]  # 剔除col1列中，值为空的无效记录。
        df2 = pd.concat([df2, df2_temp]) # 把文件夹中全部Excel文件中的Sheet2追加到模板文件的Sheet2中。

    # Calculate totals
    total_row1 = pd.DataFrame({
        '序号': ['总计'],
        'col1': [df1['col1'].sum()],
        'col2': [df1['col2'].sum()],
        'col3': [df1['col3'].sum()]
    }, index=[len(df1)])    # 按需调整Sheet1中需要计算“合计”的列的名称，可以计算多列的合计数据。
    df1 = pd.concat([df1, total_row1])  # 把合计行添加到Sheet1数据框的最后一行。

    total_row2 = pd.DataFrame({
        '序号': ['总计'],
        'col1': [df2['col1'].sum()],
        'col2': [df2['col2'].sum()],
        'col3': [df2['col3'].sum()]
    }, index=[len(df2)])   # 按需调整Sheet2中需要计算“合计”的列的名称，可以计算多列的合计数据。
    df2 = pd.concat([df2, total_row2])  # 把合计行添加到Sheet2数据框的最后一行。

    # 将data1和data2数据框转换为行列表,逐行追加到模板文件的两个工作表
    rows1 = list(dataframe_to_rows(df1, index=False, header=False))
    for row in rows1:
        ws1.append(row)

    rows2 = list(dataframe_to_rows(df2, index=False, header=False))
    for row in rows2:
        ws2.append(row)

    wb.save(writer_path)   # 保存Excel（汇总模板）文件

    window.quit()  # 关闭窗口 这行代码调用window主窗口的.quit()方法,关闭程序界面。

# 这两行代码在window主窗口上添加一个文本为“转换”、宽度为10的按钮,并绑定command事件到convert函数,也就是点击按钮后调用convert()函数。
button = tk.Button(window, text='转换', width=15, command=convert)
button.pack()

window.mainloop()  # 这行代码启动主窗口window的事件循环,用于显示窗口并等待用户交互事件。
